#include "Cache.h"
#include <fstream>
#include <sstream>
#include <stack>
#include <algorithm>
#include <iostream>

using std::ifstream;
using std::ofstream;
using std::istringstream;

Cache::Cache(int num)
    :_hashMap()
     ,_LRUlist()
     ,_updateData()
      ,_size(num)
{}

Cache::Cache(const Cache& cache)
{
    _size=cache._size;
    for(auto& elem:cache._hashMap){
        _hashMap.insert(make_pair(elem.first,elem.second));
    }
    for(auto& elem:cache._LRUlist){
        _LRUlist.push_back(make_pair(elem.first,elem.second));
    }
    for(auto& elem:cache._updateData){
        _updateData.push_back(make_pair(elem.first,elem.second));
    }
}

void Cache::addElement(const string& key,const string& value)
{
    /* cout<<"addElement"<<endl; */
    //将元素添加到更新list
    if(_updateData.empty())
        _updateData.push_front(make_pair(key,value));
    else{
        //lru策略添加元素
        LRUadd(_updateData,key,value);
    }
}

void Cache::LRUadd(list<pair<string,string>> list,const string& key,const string& value)
{
    int flag=0;
    auto it=list.begin();
    while(it!=list.end()){
        if(key==it->first){
            flag=1;
            break;
        }
        it++;
    }
    if(!flag){
        list.push_front(make_pair(key,value));
    }else{
        list.erase(it);
        list.push_front(make_pair(key,value));
    }
}
void Cache::selfUpdate()
{
    /* cout<<"selfUpdate"<<endl; */
    int size=_updateData.size();
    if(!size)
        return;
    else{
        stack<pair<string,string>> st;
        for(int i=0;i!=_size&&i!=size;i++){
            st.push(_updateData.front());
            _updateData.pop_front();
        }
        while(!st.empty()){
            if(_LRUlist.empty()){
                _LRUlist.push_front(st.top());
            }
            else{
                if((int)_LRUlist.size()==_size)
                    _LRUlist.pop_back();
                LRUadd(_LRUlist,st.top().first,st.top().second);
            }
            st.pop();
        }

        build_hashMap();
        //删除剩余元素
        _updateData.clear();
    }
}

void Cache::build_hashMap()
{
    if(!_LRUlist.size())
        return;
    _hashMap.clear();
    for(auto it=_LRUlist.begin();it!=_LRUlist.end();it++)
    {
        _hashMap.insert(make_pair(it->first,it));
    }
}
void Cache::readFromFile(const string& filename)
{
    ifstream ifs(filename);
    if(!ifs){
        perror("ifstream");
        return;
    }
    string line;
    while(getline(ifs,line)&&_size--){
        istringstream iss(line);
        string key,value;
        iss>>key>>value;
        _LRUlist.push_back(make_pair(key,value));
    }
    build_hashMap();
    ifs.close();
}

void Cache::writeToFile(const string& filename)
{
    ofstream ofs(filename);
    if(!ofs){
        perror("ofstream");
        return;
    }
    for(auto &elem:_LRUlist){
        ofs<<elem.first<<" "
            <<elem.second<<endl;
    }
    ofs.close();
}

void Cache::update(const Cache& rhs)
{
    _hashMap.clear();
    _LRUlist.clear();
    _updateData.clear();
    for(auto &elem:rhs._hashMap){
        _hashMap.insert(make_pair(elem.first,elem.second)); 
    }
    for(auto& elem:rhs._LRUlist){
        _LRUlist.push_back(make_pair(elem.first,elem.second));
    }
}

list<pair<string,string>> Cache::getLRUlist()
{
    return _LRUlist;
}

unordered_map<string,iter> Cache::gethashMap()
{
    return _hashMap;
}
